package no.ntnu.fp.net.co;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.NoSuchElementException;
import java.util.Scanner;

public class ConnectionImpl2 implements Connection {

	private Socket socket;
	private ServerSocket serverSocket;
	private PrintWriter out;
	private Scanner in;
	
	public ConnectionImpl2(int portNumber) {
		try {
			this.serverSocket = new ServerSocket(portNumber);
		} catch (IOException e) {
			throw new NetworkException(e);
		}
	}
	
	public ConnectionImpl2(Socket socket) throws IOException { 
		this.socket = socket;
		out = new PrintWriter(new BufferedOutputStream(socket.getOutputStream(), 4 * 1024));
		in = new Scanner(new BufferedInputStream(socket.getInputStream(), 4 * 1024));
		out.flush();
	}
	
	@Override
	public void connect(InetAddress remoteAddress, int remotePort)
			throws IOException {
		this.socket = new Socket(remoteAddress, remotePort);
		out = new PrintWriter(new BufferedOutputStream(socket.getOutputStream(), 4 * 1024));
		in = new Scanner(new BufferedInputStream(socket.getInputStream(), 4 * 1024));
		out.flush();
	}

	@Override
	public Connection accept()  {
		try {
			Socket acceptedSocket = serverSocket.accept();
			return new ConnectionImpl2(acceptedSocket);
		} catch (IOException e) {
			throw new NetworkException(e);
		}
	}

	@Override
	public void send(String msg) {
		out.println(msg);
		out.flush();
	}

	@Override
	public String receive() throws ConnectException, IOException,
			InterruptedException {
		try {
			return in.nextLine();
		} catch (NoSuchElementException e) {
			throw new IOException("Connection lost");
		}
	}

	@Override
	public void close() throws IOException {
		if (socket != null) {
			socket.close();
		}
		if (serverSocket != null) {
			serverSocket.close();
		}
	}

	@Override
	public boolean isConnected() {
		return socket.isConnected();
	}

	@SuppressWarnings("serial")
	private final static class NetworkException extends RuntimeException {
		public NetworkException(IOException ex) {
			super(ex);
		}
	}
	
}
